package com.qth.valet.common.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

@Slf4j
@Component
@RequiredArgsConstructor
public class WebSocketServer {

    private static final NioEventLoopGroup boss = new NioEventLoopGroup();                           // boss
    private static final NioEventLoopGroup worker = new NioEventLoopGroup();                        //work
    private static final LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);        // 日志类

    private final WebSocketServerHandler webSocketServerHandler;

    @Value("${netty.port}")
    private int port;

    @PreDestroy
    public void close() {
        boss.shutdownGracefully();
        worker.shutdownGracefully();
    }

    @PostConstruct
    public void run() {
        new Thread(() -> {
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(boss, worker)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) {
                                ChannelPipeline pipeline = ch.pipeline();
                                pipeline.addLast(LOGGING_HANDLER)
                                        // HTTP 协议的编码解码器
                                        .addLast(new HttpServerCodec())
                                        // 黏包半包处理器
                                        .addLast(new HttpObjectAggregator(64 * 1024))
                                        // 判断 读 写 空闲时间过长
                                        // 5s 内如果没有收到channel的数据，(每5秒)会触发IdleState.READER_IDLE事件
                                        .addLast(new IdleStateHandler(5, 0, 0))
                                        // 心跳
                                        .addLast(new HandlerHeartBeat())
                                        // 将http协议升级为ws协议，对websocket支持
                                        .addLast(new WebSocketServerProtocolHandler(
                                                "/dj", null, true, 1024 * 64,
                                                true, true, 10000L))
                                        // 自己的handler
                                        .addLast(webSocketServerHandler);
                            }
                        });

                Channel ch = b.bind(port).sync().channel();
                log.info("WebSocket服务器启动，端口：" + port);
                ch.closeFuture().sync();
            } catch (Exception e) {
                log.error("netty服务错误:" + e.getMessage());
            } finally {
                boss.shutdownGracefully();
                worker.shutdownGracefully();
            }
        }, "启动NETTY的线程").start();
    }
}
